package com.ybfenpan.utils;

import org.apache.poi.util.IOUtils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.*;

/**
 * 使用DES加密和解密后的方法
 * @author: qiyh
 * */
public class CryptUtil {

	public static final String keyStr = "Qiyh.123";
	private static final String ENCODING = "UTF-8";
	
	private CryptUtil(){}
	
	private static class CryptToolHolder{
		private static final CryptUtil INSTANCE = new CryptUtil();
	}
	
	public static CryptUtil getInstance(){
		return CryptToolHolder.INSTANCE;
	}
	
	/**
	 * 对字符串进行加密，可自定义秘钥key
	 * @param message
	 * @return 返回加密后的字符串
	 * @throws Exception
	 */
	public String encrypt2String(String message, String key) throws Exception {
		byte[] retByte = encrypt2Byte(message, key);
		return toHexString(retByte);
	}
	
	/**
	 * 对字符串进行加密，可自定义秘钥key
	 * @param message
	 * @return 返回加密后的byte[]
	 * @throws Exception
	 */
	public byte[] encrypt2Byte(String message, String key) throws Exception {
		byte[] bytesrc = message.getBytes(ENCODING);
		return encrypt2Byte(bytesrc, key);
	}
	
	public byte[] encrypt2Byte(byte[] byteArr, String key) throws Exception {
		byte[] keyByte = toByteArr(key, 8);
		byte[] ivByte = keyByte;
		Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
		DESKeySpec desKeySpec = new DESKeySpec(keyByte);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
		IvParameterSpec iv = new IvParameterSpec(ivByte);
		cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
		return cipher.doFinal(byteArr);
	}
	
	public void encryptFile(String sourceFile, String destFile, String key) throws Exception {
		File file = new File(sourceFile);
        if (!file.exists()) {
        	throw new FileNotFoundException("指定的文件路径不存在！"+sourceFile);
        }
		FileInputStream fis = new FileInputStream(file);
		byte[] fileByte = IOUtils.toByteArray(fis);
		byte[] retByte = encrypt2Byte(fileByte, key);
		byte2File(retByte, destFile);
    }
	
	/**
	 * 对字符串进行解密，可自定义秘钥key
	 * @param message
	 * @return 返回解密后的字符串
	 * @throws Exception
	 */
	public String decrypt2String(String message, String key) throws Exception {
		return new String(decrypt2Byte(message, key));
	}
	
	/**
	 * 对字符串进行解密，可自定义秘钥key
	 * @param message
	 * @return 返回解密后的byte[]
	 * @throws Exception
	 */
	public byte[] decrypt2Byte(String message, String key) throws Exception {
		byte[] bytesrc = convertHexString(message);
		return decrypt2Byte(bytesrc, key);
	}
	
	public byte[] decrypt2Byte(byte[] byteArr, String key) throws Exception {
		byte[] keyByte = toByteArr(key, 8);
		byte[] ivByte = keyByte;
		Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
		DESKeySpec desKeySpec = new DESKeySpec(keyByte);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
		IvParameterSpec iv = new IvParameterSpec(ivByte);
		cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
		return cipher.doFinal(byteArr);
	}
	
	public boolean decryptFile(String sourceFile, String destFile, String key) throws Exception {
		File file = new File(sourceFile);
        if (!file.exists()) {
        	throw new FileNotFoundException("指定的文件路径不存在！"+sourceFile);
        }
		FileInputStream fis = new FileInputStream(file);
		byte[] fileByte = IOUtils.toByteArray(fis);
		byte[] retByte = decrypt2Byte(fileByte, key);
		return byte2File(retByte, destFile);
	}
	
	public String toHexString(byte b[]) {
		StringBuffer hexString = new StringBuffer();
		for (int i = 0; i < b.length; i++) {
			String plainText = Integer.toHexString(0xff & b[i]);
			if (plainText.length() < 2)
				plainText = "0" + plainText;
			hexString.append(plainText);
		}
		return hexString.toString();
	}
	
	public byte[] convertHexString(String ss) {
		byte digest[] = new byte[ss.length() / 2];
		for (int i = 0; i < digest.length; i++) {
			String byteString = ss.substring(2 * i, 2 * i + 2);
			int byteValue = Integer.parseInt(byteString, 16);
			digest[i] = (byte) byteValue;
		}
		return digest;
	}
	
	public byte[] toByteArr(String str, int len){
    	byte[] newByte = new byte[8];
    	try {
    		byte[] oldByte = str.getBytes(ENCODING);
    		if(len == oldByte.length){
    			newByte = oldByte; 
    		}
    		else if(len < oldByte.length){
        		for(int i=0; i<len; i++){
        			newByte[i] = oldByte[i];
        		}
        	}
    		else if(len > oldByte.length){
    			for(int i=0; i<oldByte.length; i++){
        			newByte[i] = oldByte[i];
        		}
    			for(int i=oldByte.length; i<len-oldByte.length; i++){
        			newByte[i] = (byte)0;
        		}
    		}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return newByte;
    }
	
	//根据byte数组，生成文件
    public static boolean byte2File(byte[] bfile, String fileName) {
        BufferedOutputStream bos = null;  
        FileOutputStream fos = null;  
        File file = null;  
        try {
        	fileName = fileName.replaceAll("\\\\", "/");
        	String filePath = fileName.substring(0,fileName.lastIndexOf("/")+1);
        	
            File dir = new File(filePath);  
            if(!dir.exists()){//判断文件目录是否存在
                dir.mkdirs();  
            }  
            file = new File(fileName);
			if(file.exists()){
				file.createNewFile();
			}
            fos = new FileOutputStream(file);  
            bos = new BufferedOutputStream(fos);  
            bos.write(bfile);
			return true;
        } catch (Exception e) {  
            e.printStackTrace();
			return false;
        } finally {  
            if (bos != null) {  
                try {  
                    bos.close();  
                } catch (IOException e1) {  
                   e1.printStackTrace();  
                }  
            }  
            if (fos != null) {  
                try {  
                    fos.close();  
                } catch (IOException e1) {  
                    e1.printStackTrace();  
                }  
            }  
        }  
    } 
    
}